package com.fourtwoeight.imaging;

import java.awt.AlphaComposite;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.renderable.ParameterBlock;

import javax.media.jai.InterpolationBicubic;
import javax.media.jai.JAI;
import javax.media.jai.ParameterBlockJAI;
import javax.media.jai.PlanarImage;
import javax.media.jai.TiledImage;

/**
 *ImageHandler
 *
 *Abstracts the actions needed to open, process and save images. Since the Java Advanced Imaging and
 *Java 2D APIs are frustratingly in flux, this is a pretty basic go-between that performs ulta-simple imaging
 *processes on given images, like a PhotoShop Super LE API
 */

public class NativeJavaThumbnailProcessor implements ThumbnailProcessor {
    public static final int OVERLAY_TOP_LEFT = 1 << 1;
    public static final int OVERLAY_TOP_RIGHT = 1 << 2;
    public static final int OVERLAY_CENTER = 1 << 3;
    public static final int OVERLAY_BOTTOM_LEFT = 1 << 4;
    public static final int OVERLAY_BOTTOM_RIGHT = 1 << 5;

    PlanarImage img;

    public NativeJavaThumbnailProcessor() {

    }

    public void scaleToFit(int width, int height, String imageFile) throws Exception {
    	loadImage(imageFile);
        scaleToFit(width, height);
        saveImage(imageFile);
	}

	/**
     *@param amount The amount to scale by (i.e. 2.0F means "twice as big")
     *
     *Scales the image by the given amount
     */
    private void scale(float amount) {
        ParameterBlockJAI pb = new ParameterBlockJAI("scale");
        pb.addSource(this.img);
        pb.setParameter("xScale", amount); //x Scale Factor
        pb.setParameter("yScale", amount); //y Scale Factor
        pb.setParameter("xTrans", 0.0F);      //x Translate amount
        pb.setParameter("yTrans", 0.0F);      //y Translate amount
        pb.setParameter("interpolation", new InterpolationBicubic(1));
        this.img = JAI.create("scale", pb, null);
    }


    /**
     *@param width The width this image should be scaled to as a max
     *
     *Scales the image uniformly by calculating the scale value generated by using the width as a maximum width
     */
    private void scaleX(float width) {
        float scaleFactor;
        scaleFactor = width / (float)img.getWidth();
        scale(scaleFactor);
    }

    /**
     *@param height The height this image should be scaled to as a max
     *
     *Scales the image uniformly by calculating the scale value generated by using the height as a maximum height.
     */
    private void scaleY(float height) {
        float scaleFactor;
        scaleFactor = height / (float)img.getHeight();
        scale(scaleFactor);
    }

    /**
     *Resizes the image to fit inside the width and height given. Not guaranteed to be the exact dimensions
     *given, just fit within them.
     *@param width The maximum width to fit
     *@param height The maximum height to fit
     */
    private void scaleToFit(int width, int height) {
        if(img.getWidth() > img.getHeight()) {
            scaleX((float)width);
        } else {
            scaleY((float)height);
        }
    }

    /**
     *Loads the image from a path and filename
     *
     *@param filepath The oath and filename where the file can be found
     */
    private void loadImage(String filepath) {
        //Loads the image from the given path and filename
        this.img = (PlanarImage)JAI.create("fileload", filepath);
    }

    /**
     *Saves the image to the given path and filename
     *
     *@param filepath the path and filename to save the image to.
     */
    private void saveImage(String filepath) {
        //Saves the image to the given path and filename as a JPEG image
        saveImage(filepath, "JPEG");
    }

    /**
     *Saves the image to the given path and filename using the given codec
     *
     *@param filepath the path and filename to save the image to.
     *@param type The JAI-defined codec type to save as.
     */
    private void saveImage(String filepath, String type) {
        //Saves the image to the given path and filename
        JAI.create("filestore", img, filepath, type, null);
    }

    private void rotate(float angle) {
		ParameterBlock pb = new ParameterBlock();
		pb.addSource(img);
		pb.add(img.getWidth());
		pb.add(img.getHeight());
		pb.add(angle);
		pb.add(new InterpolationBicubic(1));
		img = JAI.create("rotate", pb);
	}


    /**
	 * @param degrees
	 *            the angle to convert
	 *
	 * Converts degrees into radians.
	 */
    private float degreesToRadians(float degrees) {
        return (float)((degrees*Math.PI)/180.0F);
    }

    /**
     *Overlays the image specified by filepath on the current image.
     *
     *@param filepath The path and file to the image to use as the overlay
     *@param alpha the amount of transparency to apply to the overlay
     */
    private void overlay(String filepath, float alpha, int align) {
        BufferedImage bi = ((PlanarImage)JAI.create("fileload", filepath)).getAsBufferedImage();
        overlay(bi, alpha, align);
    }

    /**
     *Overlays the image specified by filepath on the current image.
     *
     *@param bi The image to overlay on the current image.
     *@param alpha The amount of transparency to apply to the overlay.
     */
    private void overlay(BufferedImage bi, float alpha, int align) {
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);
        int overX, overY;
        /*
        //The following will resize the overlay image before applying it.
        //CURRENTLY NOT WORKING
        if(bi.getWidth() > this.img.getWidth()) {
            bi = (BufferedImage)bi.getScaledInstance(this.img.getWidth(), (int)((float)bi.getHeight()*((float)this.img.getWidth()/(float)bi.getWidth())), java.awt.Image.SCALE_DEFAULT);
        }
        if(bi.getHeight() > this.img.getHeight()) {
            bi = (BufferedImage)bi.getScaledInstance((int)((float)bi.getWidth()*((float)this.img.getHeight()/(float)bi.getHeight())), this.img.getHeight(), java.awt.Image.SCALE_DEFAULT);
        }*/
        if(align == OVERLAY_BOTTOM_RIGHT){
            overX = this.img.getMaxX() - bi.getWidth();
            overY = this.img.getMaxY() - bi.getHeight();
        } else if(align == OVERLAY_BOTTOM_LEFT) {
            overX = 0;
            overY = this.img.getMaxY() - bi.getHeight();
        } else if(align == OVERLAY_TOP_RIGHT) {
            overX = this.img.getMaxX() - bi.getWidth();
            overY = 0;
        } else if(align == OVERLAY_CENTER) {
            overX = this.img.getWidth()/2 - bi.getWidth()/2;
            overY = this.img.getHeight()/2 - bi.getHeight()/2;
        } else {
            overX = 0;
            overY = 0;
        }

        TiledImage ti = new TiledImage(this.img, false);
        Graphics2D g2 = ti.createGraphics();
        g2.setComposite(ac);
        g2.drawImage(bi, overX, overY, null);
        this.img = ti;
    }

    private void overlayText(String text, float alpha, int align, Font f, java.awt.Color col) {
        TiledImage ti = new TiledImage(this.img, false);
        Graphics2D g2 = ti.createGraphics();
        AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha);

        int overX, overY;
        java.awt.font.FontRenderContext frc = g2.getFontRenderContext();
        java.awt.font.TextLayout layout = new java.awt.font.TextLayout(text, f, frc);
        java.awt.geom.Rectangle2D rect = layout.getBounds();

        if(align == OVERLAY_BOTTOM_RIGHT){
            overX = this.img.getMaxX() - (int)rect.getWidth();
            overY = this.img.getMaxY() - (int)rect.getHeight();
        } else if(align == OVERLAY_BOTTOM_LEFT) {
            overX = 0;
            overY = this.img.getMaxY() - (int)rect.getHeight();
        } else if(align == OVERLAY_TOP_RIGHT) {
            overX = this.img.getMaxX() - (int)rect.getWidth();
            overY = 0;
        } else if(align == OVERLAY_CENTER) {
            overX = this.img.getWidth()/2 - (int)rect.getWidth()/2;
            overY = this.img.getHeight()/2 - (int)rect.getHeight()/2;
        } else {
            overX = 0;
            overY = 0;
        }
        g2.setComposite(ac);
        g2.setFont(f);
        g2.setColor(col);
        g2.drawString(text, overX, overY);
        this.img = ti;
    }

    private BufferedImage getCurrentImage() {
        return img.getAsBufferedImage();
    }

    public static void main(String[] args) {
        if(args.length < 2) {
            System.out.println("Usage: java com.robzazueta.imagemaker.ImageHandler [inputfilename] [outputfilename]");
            System.exit(0);
        }

        NativeJavaThumbnailProcessor ih = new NativeJavaThumbnailProcessor();
        ih.loadImage(args[0]);
        ih.scale(2.0F);
        ih.saveImage(args[1]);
        System.out.println("Done!\n");
    }

}